#include <common.h>
#include <cvector.h>
#include <filesystem.h>
#include <object/student.h>
#include <object/building.h>
#include <stdarg.h>
#include <time.h> // TDOO register a student with time

#define STUDENTS_CFG_PATH \
    HOSTEL_MANAGER_HOME_DIR "students.cfg"

#define REGISTER_LOG_PATH \
    HOSTEL_MANAGER_HOME_DIR "register.log"

static cvector(Student) student_list = NULL;

HM_private
void save_students(void) {
    FILE *config = fopen(STUDENTS_CFG_PATH, "w");
    for (size_t i = 0; i != cvector_size(student_list); ++i) {
        fprintf(
            config,
            "%zu %zu %zu %zu\n",
            student_list[i].student_id,
            student_list[i].hostel_id,
            student_list[i].building_id,
            student_list[i].bed_id
        );
    }
    fclose(config);
}

HM_private
void add_register_log_info(char const*const format, ...) {
    FILE *register_log = fopen(REGISTER_LOG_PATH, "a");
    if (register_log == NULL) {
        HM_throw(InternalError, "failed to open register.log");
    }
    va_list args;
    va_start(args, format);
    vfprintf(register_log, format, args);
    va_end(args);
    fclose(register_log);
}

void register_student(
        size_t student_id,
        size_t hostel_id,
        size_t building_id,
        size_t bed_id,
        bool should_register
) {
    Student student = {
        .student_id = student_id,
        .hostel_id = hostel_id,
        .building_id = building_id,
        .bed_id = bed_id
    };
    if (get_student(student_id) != NULL) {
        printf("student %zu already registered\n", student_id);
        return;
    }
    cvector_push_back(student_list, student);
    save_students();

    if (should_register) {
        add_register_log_info("[register] students: %zu\n", student_id);
    }
}

HM_private
void load_students(void) {
    char buffer[32] = {0};
    FILE *config = fopen(STUDENTS_CFG_PATH, "r");
    if (config == NULL) {
        HM_throw(InternalError, "can't open students.cfg file");
    }

    while (read_line(config, buffer, sizeof(buffer))) {
        size_t student_id, hostel_id, building_id, bed_id;
        if (sscanf_s(
                buffer, "%zu %zu %zu %zu",
                &student_id, &hostel_id,
                &building_id, &bed_id
            ) <= 0
        ) {
            HM_throw(InternalError, "invalid config file");
        }

        register_student(student_id, hostel_id, building_id, bed_id, false);
    };

    fclose(config);
}

/* @return: 0: success, 1: fail
 */
int unregister_student(size_t student_id) {
    for (size_t i = 0; i != cvector_size(student_list); ++i) {
        if (student_list[i].student_id == student_id) {
            cvector_erase(student_list, i);
            save_students();
            add_register_log_info("[unregister] students: %zu\n", student_id);
            return 0;
        }
    }
    return 1;
}

/* @return: 0: success, 1: student not found
 */
int edit_student(size_t student_id, size_t hostel_id, size_t building_id, size_t bed_id) {
    for (size_t i = 0; i != cvector_size(student_list); ++i) {
        if (student_list[i].student_id == student_id) {
            student_list[i].hostel_id = hostel_id;
            student_list[i].building_id = building_id;
            student_list[i].bed_id = bed_id;
            save_students();
            return 0;
        }
   }
   return 1;
}

void print_student(Student const*const student) {
    printf(
        "student id: %zu, hostel id: %zu, building id: %zu, bed_id: %zu\n",
        student->student_id,
        student->hostel_id,
        student->building_id,
        student->bed_id
    );
}

void list_students(void) {
    for (size_t i = 0; i != cvector_size(student_list); ++i) {
        print_student(&student_list[i]);
    }
}

/* @return NULL if not found, otherwise return the student ptr
 */
Student* get_student(size_t student_id) {
    for (size_t i = 0; i != cvector_size(student_list); ++i) {
        if (student_list[i].student_id == student_id) {
            return &student_list[i];
        }
    }
    return NULL;
}

size_t count_students_in_a_hostel(size_t hostel_id) {
    size_t res = 0;
    for (size_t i = 0; i != cvector_size(student_list); ++i) {
        if (student_list[i].hostel_id == hostel_id) {
            ++res;
        }
    }
    return res;
}

void list_students_in_a_hostel(size_t hostel_id, size_t building_id) {
    for (size_t i = 0; i != cvector_size(student_list); ++i) {
        if (student_list[i].hostel_id == hostel_id && student_list[i].building_id == building_id) {
            print_student(&student_list[i]);
        }
    }
}

// void print_vacant_beds(bool is_male) {
//     cvector(size_t) used_beds = NULL;
//     for (size_t i = 0; i != cvector_size(student_list); ++i) {
//         Building *building = get_building(student_list[i].building_id);
//         if (building->is_male == is_male && student_list[i].studen) {
//             printf("Bed ID: %zu\n", bed_list[i].bed_id);
//         }
//     }
// }

void info_register_log(void) {
    FILE *register_log = fopen(REGISTER_LOG_PATH, "r");
    if (register_log == NULL) {
        HM_throw(InternalError, "failed to open register.log");
    }
    char buffer[32] = {0};
    while (read_line(register_log, buffer, sizeof(buffer))) {
        printf("%s\n", buffer);
    }
    fclose(register_log);
}

void init_student_module(void) {
    crt_file_if_not_exist(STUDENTS_CFG_PATH);
    crt_file_if_not_exist(REGISTER_LOG_PATH);
    load_students();
}
